package Controlador;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Vector;

import Negocio.AnteriorCosechaGruesa;
import Negocio.Cereal;
import Negocio.CerealCosechaFina;
import Negocio.CerealCosechaFinaView;
import Negocio.CerealCosechaGruesa;
import Negocio.CerealCosechaGruesaView;
import Negocio.CerealView;
import Negocio.Cosecha;
import Negocio.ItemMineral;
import Negocio.ItemMineralView;
import Negocio.Lote;
import Negocio.LoteCompuesto;
import Negocio.LoteCompuestoView;
import Negocio.LoteSimple;
import Negocio.LoteSimpleView;
import Negocio.LoteView;
import Negocio.MayorRinde;
import Negocio.MinNoSupera40;
import Negocio.Mineral;
import Negocio.MineralView;
import Negocio.Propietario;
import Negocio.PropietarioView;
import Negocio.ReglaNegocio;
import Negocio.Siembra;
import Negocio.VectorNegocio;
import Persistencia.AdmPersistenciaCereal;
import Persistencia.AdmPersistenciaCerealCosechaFina;
import Persistencia.AdmPersistenciaCerealCosechaGruesa;
import Persistencia.AdmPersistenciaLote;
import Persistencia.AdmPersistenciaLoteCompuesto;
import Persistencia.AdmPersistenciaLoteSimple;
import Persistencia.AdmPersistenciaMineral;
import Persistencia.AdmPersistenciaPropietario;
import Persistencia.AdmPersistenciaSiembra;

public class Sistema {
	private static Sistema instancia;

	private VectorNegocio cereal;
	private VectorNegocio cerealcosechafina;
	private VectorNegocio cerealcosechagruesa;
	private VectorNegocio lotes;
	private VectorNegocio lotesSimples;
	private VectorNegocio lotesCompuestos;
	private VectorNegocio minerales;
	private VectorNegocio propietarios;
	private VectorNegocio cosechas;
	private VectorNegocio itemMinerales;
	private VectorNegocio siembras;
	private Vector<ReglaNegocio> reglas;

	private AdmPersistenciaCereal CerealPersistencia;
	private AdmPersistenciaCerealCosechaFina CosechaFinaPersistencia;
	private AdmPersistenciaCerealCosechaGruesa CosechaGruesaPersistencia;
	private AdmPersistenciaMineral MineralPersistencia;


	private AdmPersistenciaLoteSimple LoteSimplePersistencia;
	private AdmPersistenciaLoteCompuesto LoteCompuestoPersistencia;
	private AdmPersistenciaLote LotePersistencia;
	private AdmPersistenciaPropietario PropietarioPersistencia;
	private AdmPersistenciaSiembra SiembraPersistencia;

	private Utils utils;

	public Sistema() {

		CosechaFinaPersistencia = AdmPersistenciaCerealCosechaFina
				.getInstancia();
		CosechaGruesaPersistencia = AdmPersistenciaCerealCosechaGruesa
				.getInstancia();

		LoteSimplePersistencia = AdmPersistenciaLoteSimple.getInstancia();
		LoteCompuestoPersistencia = AdmPersistenciaLoteCompuesto.getInstancia();
		LotePersistencia = AdmPersistenciaLote.getInstancia();
		MineralPersistencia = AdmPersistenciaMineral.getInstancia();
		PropietarioPersistencia = AdmPersistenciaPropietario.getInstancia();
		CerealPersistencia = AdmPersistenciaCereal.getInstancia();
		SiembraPersistencia = AdmPersistenciaSiembra.getInstancia();

		reglas = new Vector<ReglaNegocio>();
		reglas.add(new MinNoSupera40());
		reglas.add(new AnteriorCosechaGruesa());
		reglas.add(new MayorRinde());
		cereal = new VectorNegocio();
		cereal.addAll(CerealPersistencia.selectAll());
		cerealcosechafina = new VectorNegocio();
		cerealcosechagruesa = new VectorNegocio();
		minerales = new VectorNegocio();
		minerales.addAll(MineralPersistencia.selectAll());
		propietarios = new VectorNegocio();
		propietarios.addAll(PropietarioPersistencia.selectAll());
		lotes = new VectorNegocio();
		lotesSimples = new VectorNegocio();
		lotesCompuestos = new VectorNegocio();
		cosechas = new VectorNegocio();
		itemMinerales = new VectorNegocio();
		siembras = new VectorNegocio();

		utils = Utils.getInstancia();

	}

	public static Sistema getInstancia() {
		if (instancia == null)
			instancia = new Sistema();
		return instancia;
	}

	private CerealCosechaFina obtenerCerealCosechaFina(long cod) {
		System.out.println("LOG: Sistem / buscarCerealCosechaFina [INI]");
		CerealCosechaFina c = (CerealCosechaFina) cerealcosechafina
				.buscarPorCodigo(cod);

		if (c == null) {

			c = (CerealCosechaFina) CosechaFinaPersistencia
					.buscarPorCodigo(cod);

			if (c != null) {

				cereal.add(c);
				cerealcosechagruesa.add(c);
				System.out
						.println("LOG: Sistem / buscarCerealCosechaFina [FIN]");
				return c;

			} else {

				// TODO Exception
				System.out.println("Excepcion: No existe el cereal");
				System.out.println("LOG: Sistem / []");
				return null;
			}

		} else {

			System.out.println("LOG: Sistem / buscarCerealCosechaFina [FIN]");
			return c;

		}

	}

	public CerealCosechaFinaView buscarCerealCosechaFina(long cod) {
		return obtenerCerealCosechaFina(cod).getView();

	}

	public void AltaCerealCosechaFina(String nom, int ini, int fin,
			MineralView m, double r) {
		System.out.println("LOG: Sistem / AltaCerealCosechaFina [INI]");
		CerealCosechaFina alt = (CerealCosechaFina) CosechaFinaPersistencia
				.buscarPorNombre(nom);

		if (alt != null) {
			System.out.println("Ya existe el Cereal cosecha fina");
		} else {
			Mineral min = (Mineral) MineralPersistencia.buscarPorCodigo(m
					.getCodigo());
			CerealCosechaFina c = new CerealCosechaFina(
					Utils.CONSTANTE_INT_SIN_USO, nom, ini, fin, r,
					Utils.CONSTANTE_ACTIVO, min);

			c.insert();
			cereal.add(c);
			cerealcosechafina.add(c);
		}
		System.out.println("LOG: Sistem / AltaCerealCosechaFina [FIN]");

	}

	public void modificarCerealCosechaFina(CerealCosechaFinaView a) {
		System.out.println("LOG: Sistema / modificarCerealCosechaFina [INI]");
		CerealCosechaFina c = obtenerCerealCosechaFina(a.getCodigo());

		if (c != null) {

			c.setFinEpocaSiembra(a.getFinEpocaSiembra());
			c.setInicioEpocaSiembra(a.getInicioEpocaSiembra());
			c.setCodigo(a.getCodigo());
			c.setNombre(a.getNombre());
			c.setRinde(a.getRinde());
			c.setEstado(a.getEstado());
			c.update();

		} else {

			// TODO Exception
			System.out.println("El cereal no existe");

		}

		System.out.println("LOG: Sistema / modificarCerealCosechaFina [FIN]");

	}

	private CerealCosechaGruesa obtenerCosechaGruesa(long cod) {
		System.out.println("LOG: Sistem / buscarCerealCosechaGruesa [INI]");
		CerealCosechaGruesa c = (CerealCosechaGruesa) cerealcosechagruesa
				.buscarPorCodigo(cod);

		if (c == null) {

			c = (CerealCosechaGruesa) CosechaGruesaPersistencia
					.buscarPorCodigo(cod);

			if (c != null) {

				cereal.add(c);
				cerealcosechagruesa.add(c);
				System.out
						.println("LOG: Sistem / buscarCerealCosechaGruesa [FIN]");
				return c;

			} else {

				// TODO Exception
				System.out.println("Excepcion: No existe el cereal");
				System.out.println("LOG: Sistem / []");
				return null;

			}
		} else {

			System.out.println("LOG: Sistem / buscarCerealCosechaGruesa [FIN]");
			return c;

		}

	}

	public CerealCosechaGruesaView buscarCerealCosechaGruesa(long cod) {
		return obtenerCosechaGruesa(cod).getView();

	}

	public void AltaCerealCosechaGruesa(String nom, Integer ini, Integer fin,
			double rinde, double desp, MineralView mv) {
		System.out.println("LOG: Sistem / AltaCerealCosechaGruesa [INI]");

		// TODO Manejar de excepcion de base de datos
		CerealCosechaGruesa alt = (CerealCosechaGruesa) CosechaGruesaPersistencia
				.buscarPorNombre(nom);

		if (alt != null) {
			System.out.println("EXISTE EL CEREAL DE COSECHA GRUESA");
		} else {
			Mineral min = (Mineral) AdmPersistenciaMineral.getInstancia()
					.buscarPorCodigo(mv.getCodigo());
			CerealCosechaGruesa c = new CerealCosechaGruesa(
					Utils.CONSTANTE_LONG_SIN_USO, nom, ini, fin, rinde,
					Utils.CONSTANTE_ACTIVO, desp, min);
			c.insert();
			cereal.add(c);
			cerealcosechagruesa.add(c);
			System.out.println("LOG: Sistem / AltaCerealCosechaGruesa [FIN]");
		}
	}

	public Cereal obtenerCereal(long cod) {
		System.out.println("LOG: Sistem / buscarCereal [INI]");

		Cereal c = (Cereal) cereal.buscarPorCodigo(cod);

		if (c == null)
			c = (Cereal) CerealPersistencia.buscarPorCodigo(cod);

		if (c != null) {
			System.out.println("LOG: Sistema / buscarCereal [FIN]");
			return c;
		}

		System.out.println("LOG: Sistema / buscarCereal [FIN]");
		return null;

	}

	public CerealView buscarCereal(long cod) {
		return obtenerCereal(cod).getView();

	}

	public void eliminarCereal(long cod) {
		// TODO todavia no me termina de convecer
		System.out.println("LOG: Sistema / eliminarCereal [INI]");

		Cereal cer = obtenerCereal(cod);

		cereal.eleminiarPorCodigo(cod);
		cerealcosechafina.eleminiarPorCodigo(cod);
		cerealcosechagruesa.eleminiarPorCodigo(cod);

		cer.delete();

		System.out.println("LOG: Sistema / eliminarCereal [FIN]");
	}

	public void modificarCerealCosechaGruesa(CerealCosechaGruesaView a) {
		System.out.println("LOG: Sistema / modificarCerealCosechaGruesa [INI]");
		CerealCosechaGruesa c = obtenerCosechaGruesa(a.getCodigo());
		if (c != null) {
			c.setFinEpocaSiembra(a.getFinEpocaSiembra());
			c.setInicioEpocaSiembra(a.getInicioEpocaSiembra());
			c.setCodigo(a.getCodigo());
			c.setNombre(a.getNombre());
			c.setRinde(a.getRinde());
			c.setEstado(a.getEstado());
			c.setDesperdicio(a.getDesperdicio());
			c.update();
		} else {
			// TODO Exception
			System.out.println("El cereal no se puede modificar");
		}
		System.out.println("LOG: Sistema / modificarCerealCosechaGruesa [FIN]");
	}

	private LoteSimple obtenerLoteSimple(Long nroLote) {
		System.out.println("LOG: Sistema / []");
		LoteSimple lote = (LoteSimple) lotes.buscarPorCodigo(nroLote);

		if (lote == null)
			lote = (LoteSimple) LoteSimplePersistencia.buscarPorCodigo(nroLote);

		System.out.println("LOG: Sistema / []");

		return lote;

	}

	public LoteSimpleView buscarLoteSimple(Long nroLote) {

		return obtenerLoteSimple(nroLote).getView();

	}

	public void AltaLoteSimple(ItemMineralView minPrin,
			Collection<ItemMineralView> minComp, double areaSi,
			PropietarioView p) {

		System.out.println("LOG: Sistema / AltaLoteSimple [INI]");

		ItemMineral itemPrincipal = new ItemMineral(
				Utils.CONSTANTE_INT_SIN_USO, minPrin.getMineral().getCodigo(),
				minPrin.getPorcentaje(), Utils.CONSTANTE_LONG_SIN_USO,
				Utils.CONSTANTE_PRIMARIO);

		Propietario prop = (Propietario) PropietarioPersistencia
				.buscarPorCodigo(p.getDni());

		// TODO validaciones
		LoteSimple loteS = new LoteSimple(Utils.CONSTANTE_LONG_SIN_USO,
				itemPrincipal, Utils.CONSTANTE_LOTE_SIMPLE, utils
						.pasarVectorItem(minComp), areaSi, prop,
				Utils.CONSTANTE_ACTIVO);

		loteS.insert();
		lotes.add(loteS);
		lotesSimples.add(loteS);
		itemMinerales.add(loteS.getMineralPrincipal());
		itemMinerales.addAll(loteS.getMineralesComponentes());

		System.out.println("LOG: Sistema / AltaLoteSimple [FIN]");

	}

	public void ModificarLoteSimple(long nro, ItemMineralView minPrin,
			Collection<ItemMineralView> minComp, Double areaSiembra, Long p) {

		System.out.println("LOG: Sistema / ModificarLoteSimple [INI]");

		LoteSimple lote = obtenerLoteSimple(nro);
		Propietario prop = obtenerPropietario(p);

		if (lote == null) {
			// TODO Exception
			System.out.println("El lote no existe");
		} else {

			ItemMineral itemPrincipal = new ItemMineral(
					Utils.CONSTANTE_INT_SIN_USO, minPrin.getMineral()
							.getCodigo(), minPrin.getPorcentaje(), nro,
					Utils.CONSTANTE_PRIMARIO);

			lote.setProp(prop);
			lote.setAreaSiembra(areaSiembra);
			lote.setMineralPrincipal(itemPrincipal);
			lote.setMineralesComponentes(utils.pasarVectorItem(minComp));
			lote.update();

		}

		System.out.println("LOG: Sistema / ModificarLoteSimple [FIN]");

	}

	private Propietario obtenerPropietario(Long p) {
		return (Propietario) propietarios.buscarPorCodigo(p);
	}

	public void eliminarLote(Long nroLote) {

		System.out.println("LOG: Sistema / eliminarLoteSimple [INI]");

		Lote ls = obtenerLote(nroLote);

		if (ls != null) {

			ls.delete();

			System.out.println("LOG: Sistema / eliminarLoteSimple [FIN]");
		} else {

			System.out.println("LOG: Sistema / eliminarLoteSimple [FIN]");
		}
	}

	private Lote obtenerLote(Long nroLote) {
		System.out.println("LOG: Sistema / buscarLote [INI]");

		Lote lote = (Lote) lotes.buscarPorCodigo(nroLote);

		if (lote == null)
			lote = (Lote) LotePersistencia.buscarPorCodigo(nroLote);

		System.out.println("LOG: Sistema / buscarLote [INI]");
		return lote;
	}

	public LoteView buscarLote(Long nroLote) {
		return obtenerLote(nroLote).getView();
	}

	public Vector<Mineral> getMinerales() {
		System.out.println("LOG: Sistema / getMinerales []");

		return MineralPersistencia.selectAll();

	}

	private Mineral obtenerMineral(String text) {

		System.out.println("LOG: Sistema / buscarMineral [INI]");

		Mineral m = null;
		for (Object o : minerales) {
			m = (Mineral) o;
			if (m.getNombre().equals(text))
				return m;
		}

		if (m == null)
			m = (Mineral) MineralPersistencia.buscarPorNombre(text);

		if (m == null) {
			// TODO Exception
			System.out.println("El mineral no existe");
		}
		System.out.println("LOG: Sistema / buscarMineral [FIN]");
		return m;
	}

	public Mineral obtenerMineral(Long codigo) {

		System.out.println("LOG: Sistema / buscarMineral [INI]");
		Mineral m = (Mineral) minerales.buscarPorCodigo(codigo);
		if (m == null)
			m = (Mineral) MineralPersistencia.buscarPorCodigo(codigo);

		if (m == null) {
			// TODO Exception
			System.out.println("El mineral no existe");
		}
		System.out.println("LOG: Sistema / buscarMineral [FIN]");
		return m;

	}

	public MineralView buscarMineral(String text) {
		return obtenerMineral(text).getView();
	}

	public void AltaCosecha(String fechaInicio, String fechaFin,
			Double cantidadCosechada, CerealView cerealCosechado, Long l) {

		System.out.println("LOG: Sistema / AltaCosecha [INI]");

		Cereal ce = obtenerCereal(cerealCosechado.getCodigo());

		Cosecha c = new Cosecha(Utils.CONSTANTE_LONG_SIN_USO, fechaInicio,
				fechaFin, cantidadCosechada, ce, l, Utils.CONSTANTE_ACTIVO);
		c.insert();
		cosechas.add(c);
		System.out.println("LOG: Sistema / AltaCosecha [FIN]");

	}

	private LoteCompuesto obtenerLoteCompuesto(Long nroLote) {
		System.out.println("LOG: Sistema / []");
		LoteCompuesto lote = (LoteCompuesto) lotes.buscarPorCodigo(nroLote);

		if (lote == null)
			lote = (LoteCompuesto) LoteCompuestoPersistencia
					.buscarPorCodigo(nroLote);

		System.out.println("LOG: Sistema / []");

		return lote;

	}

	public LoteCompuestoView buscarLoteCompuesto(Long nroLote) {

		return obtenerLoteCompuesto(nroLote).getView();

	}

	public void AltaLoteCompuesto(PropietarioView p, ArrayList<Long> l) {

		System.out.println("LOG: Sistema / AltaLoteSimple [INI]");

		Propietario prop = (Propietario) PropietarioPersistencia
				.buscarPorCodigo(p.getDni());
		Vector<Lote> lc = new Vector<Lote>();
		for (Long lo : l) {
			lc.add((Lote) LotePersistencia.buscarPorCodigo(lo));
		}

		LoteCompuesto loteC = LoteCompuesto.getLote(prop, lc);

		lotesCompuestos.add(loteC);
		itemMinerales.add(loteC.getMineralPrincipal());
		itemMinerales.addAll(loteC.getMineralesComponentes());

		System.out.println("LOG: Sistema / AltaLoteSimple [FIN]");

	}

	public void ModificarLoteCompuesto(long m, ArrayList<Long> loteComp, long p) {

		System.out.println("LOG: Sistema / ModificarLoteSimple [INI]");

		LoteCompuesto lote = obtenerLoteCompuesto(m);

		Propietario prop = obtenerPropietario(p);

		if (lote == null) {
			// TODO Exception
			System.out.println("El lote no existe");
		} else {

			Collection<ItemMineral> it = lote.getMineralesComponentes();
			it.add(lote.getMineralPrincipal());
			eliminarItems(it);
			Vector<Lote> lotesComponentes = new Vector<Lote>();
			for (Long l : loteComp) {
				lotesComponentes.add(obtenerLote(l));
			}
			lote.setLotesComponentes(lotesComponentes);
			lote.setProp(prop);
			lote.update();

		}

		System.out.println("LOG: Sistema / ModificarLoteSimple [FIN]");

	}

	private void eliminarItems(Collection<ItemMineral> it) {
		itemMinerales.removeAll(it);
		for (ItemMineral i : it)
			i.delete();

	}

	public Vector<CerealView> buscarCereales() {

		Vector<CerealView> cer = utils.pasasrVectorCerealView(cereal);
		return cer;

	}

	public Vector<MineralView> buscarminerales() {

		Vector<MineralView> min = utils.pasarVectorMineralView(minerales);
		return min;

	}

	public Vector<PropietarioView> buscarPropietarios() {

		Vector<PropietarioView> prop = utils
				.pasarVectorPropiertarioView(propietarios);
		return prop;

	}

	public Vector<Long> buscarLotes() {
		Vector<Long> res = new Vector<Long>();
		for (Object o : LotePersistencia.buscarTodos()) {
			Long l = (Long) o;
			res.add(l);
		}
		return res;
	}

	public void generarSiembras() {
		Vector<Lote> lotes = obtenerLotesDisponibles();
		VectorNegocio cer = new VectorNegocio();
		
		Cereal c = null;
		siembras.addAll(obtenerSiembras());
		for (Lote l : lotes) {
			cer.addAll(cereal);
			for (ReglaNegocio r : reglas) {
				cer = r.obtenerCereal(l, cer);
			}
			if (cer.size() == 1) {
				c = (Cereal) cer.get(0);

			}
			if (c != null) {
				
				Siembra si = null;
				for (Object s : siembras) {

					if (c.equals(((Siembra)s).getCereal())) 
						si = (Siembra)s;
				}	
					if (si==null)
						altaSiembra(siembras,c, l);	
					else
						si.addLote(l);
					
				
			}
			cer.clear();
		}
		try {
			finalize();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void altaSiembra(Vector<Object> siembras, Cereal c, Lote l) {

		Vector<Lote> lotes = new Vector<Lote>();
		lotes.add(l);
		Siembra s = new Siembra(Utils.CONSTANTE_LONG_SIN_USO, c, c.sembrada(l.getAreaSiembra()), lotes);
		s.insert();
		siembras.add(s);
		
	}

	private Vector<Siembra> obtenerSiembras() {
		Vector<Siembra> res = new Vector<Siembra>();
		for (Object o : SiembraPersistencia.buscarTodos())
			res.add((Siembra) o);
		return res;
	}

	private Vector<Lote> obtenerLotesDisponibles() {
		Vector<Lote> res = new Vector<Lote>();
		Vector<Object> lotes = LotePersistencia.buscarTodosdis();
		for (Object o : lotes){
			Lote l = obtenerLote((Long)o);
			if(l.disponible())
				res.add(l);
		}
		return res;
	}

}
